 `timescale 1ns/1ps
`include "../define.sv"

/*module pe_tb();
    // 枚举类型定义
    typedef enum {IDLE_PHASE, MULT_PHASE, ADD_PHASE, LOAD_PHASE} PHASE_TYPE;
    
    // 接口信号声明
    reg clk;
    reg reset;
    reg [1:0] data_type;
    reg mult_en;
    reg c_add_en;
    reg [`DATA_WIDTH-1:0] a_in;
    reg [`DATA_WIDTH-1:0] b_in;
    reg [`DATA_WIDTH-1:0] c_in;
    wire [`DATA_WIDTH-1:0] a_out;
    wire [`DATA_WIDTH-1:0] b_out;
    wire [`DATA_WIDTH-1:0] c_out;
    wire add_valid_o;

    // 灰盒信号接入（直接通过层次路径）
    wire [`DATA_WIDTH-1:0] internal_acc    = uut.accumulator;
    wire [`DATA_WIDTH-1:0] internal_mult   = uut.mult_out;
    wire internal_mult_valid               = uut.mult_valid;
    wire internal_add_en                   = uut.add_inst.valid2;

    pe uut (
        .clk(clk),
        .reset(reset),
        .data_type(data_type),
        .mult_en(mult_en),
        .c_add_en(c_add_en),
        .a_in(a_in),
        .b_in(b_in),
        .c_in(c_in),
        .a_out(a_out),
        .b_out(b_out),
        .c_out(c_out),
        .add_valid_o(add_valid_o)
    );

    // 时钟生成（200MHz）
    initial begin
        clk = 0;
        forever #2.5 clk = ~clk;
    end

    // 智能Monitor类（不依赖接口）
    class PipelineMonitor;
        task run();
            forever begin
                fork
                    monitor_multiplication();
                    monitor_addition();
                    monitor_loading();
                join_none
                #1;
            end
        endtask

        task monitor_multiplication();
            forever begin
                @(posedge uut.clk iff uut.mult_en);
                $display("[MULT] @%0t: a=0x%h, b=0x%h", 
                         $time, uut.a_in, uut.b_in);
                @(posedge uut.clk); // 等待乘法延迟
                if(uut.mult_valid)
                    $display("[MULT] @%0t: result=0x%h", 
                            $time, uut.mult_out);
            end
        endtask

        task monitor_addition();
            forever begin
                @(posedge uut.add_valid_o);
                $display("[ADD] @%0t: acc=0x%h, sum=0x%h", 
                         $time, uut.accumulator, uut.c_out);
            end
        endtask

        task monitor_loading();
            forever begin
                @(posedge uut.clk iff uut.c_add_en);
                $display("[LOAD] @%0t: c_in=0x%h -> acc=0x%h", 
                        $time, uut.c_in, uut.accumulator);
            end
        endtask
    endclass

    // 关键时序断言
    property mult_pipeline_prop;
        @(posedge clk) disable iff(reset)
        (mult_en && !c_add_en) |-> ##1 internal_mult_valid;
    endproperty

    property add_pipeline_prop;
        @(posedge clk) disable iff(reset)
        internal_mult_valid |-> ##1 add_valid_o;
    endproperty

    assert property (mult_pipeline_prop)
        else $error("乘法器流水线延迟错误!");
    assert property (add_pipeline_prop)
        else $error("加法器流水线延迟错误!");

    initial begin
        automatic PipelineMonitor mon = new();
        fork
            mon.run();
        join_none

        // 初始化
        reset = 1;
        {mult_en, c_add_en} = 0;
        {a_in, b_in, c_in} = 0;
        data_type = 2'b01; // INT8模式
        #20 reset = 0;

        // 测试1：C加载功能
        c_add_en = 1;
        c_in = 8'h10;
        #10;
        check_state(1, .exp_acc(8'h10), 
                 .exp_cout(8'h10),
                 .check_phase(LOAD_PHASE));

        // 测试2：单次乘加操作
        c_add_en = 0;
        mult_en = 1;
        a_in = 8'h03;
        b_in = 8'h04;
        #20; // 等待两个周期
        check_state(2, .exp_acc(8'h0C),
                 .exp_cout(8'h0C),
                 .check_phase(ADD_PHASE));

        // 测试3：连续流水线操作
        fork
            begin // 数据生成线程
                for(int i=1; i<=4; i++) begin
                    a_in = i;
                    b_in = i+1;
                    #10;
                end
            end
            
            begin // 结果检查线程
                #15; // 跳过第一个结果
                check_sequence(3, '{8'h03, 8'h0C+8'h08, 8'h0C+8'h08+8'h18});
            end
        join

        // 测试4：混合模式操作
        mult_en = 0;
        c_add_en = 1;
        c_in = 8'h20;
        #10;
        mult_en = 1;
        c_add_en = 0;
        a_in = 8'hFF; // -1
        b_in = 8'hFE; // -2
        #20;
        check_state(4, .exp_acc(8'h20 + 8'h02), 
                 .exp_cout(8'h20 + 8'h02),
                 .check_phase(ADD_PHASE));

        $display("\n=== 所有时序测试通过 ===");
        $finish;
    end

    // 增强检查任务
    task automatic check_state;
        input integer test_id;
        input [`DATA_WIDTH-1:0] exp_acc;
        input [`DATA_WIDTH-1:0] exp_cout;
        input PHASE_TYPE check_phase;
        begin
            case(check_phase)
                ADD_PHASE: @(posedge add_valid_o); // 等待加法完成
                MULT_PHASE: @(posedge internal_mult_valid);
                LOAD_PHASE: @(posedge c_add_en);
                default: #1;
            endcase
            
            if(internal_acc !== exp_acc)
                $error("[Test%0d] 累加器错误! 预期:0x%h 实际:0x%h",
                      test_id, exp_acc, internal_acc);
            if(c_out !== exp_cout)
                $error("[Test%0d] 输出错误! 预期:0x%h 实际:0x%h",
                      test_id, exp_cout, c_out);
            $display("[Test%0d] 阶段检查通过", test_id);
        end
    endtask

    // 流水线序列检查
    task automatic check_sequence;
        input integer test_id;
        input bit [`DATA_WIDTH-1:0] exp_values[$];
        foreach(exp_values[i]) begin
            @(posedge add_valid_o);
            if(internal_acc !== exp_values[i])
                $error("[Test%0d] 第%d次累加错误! 预期:0x%h 实际:0x%h",
                      test_id, i+1, exp_values[i], internal_acc);
        end
        $display("[Test%0d] 流水线序列检查通过", test_id);
    endtask

    // 自动时序检查
    always @(posedge clk) begin
        if(mult_en && !reset) begin
            // 检查输入寄存器延迟
            static reg [`DATA_WIDTH-1:0] prev_a, prev_b;
            #0.1; // 避免竞争
            if(prev_a !== a_in) begin
                assert(a_out === prev_a) 
                    else $error("A通路延迟错误");
                prev_a = a_in;
            end
            if(prev_b !== b_in) begin
                assert(b_out === prev_b)
                    else $error("B通路延迟错误");
                prev_b = b_in;
            end
        end
    end
endmodule */
module pe_tb();
    // 枚举类型定义
    typedef enum {IDLE_PHASE, MULT_PHASE, ADD_PHASE, LOAD_PHASE} PHASE_TYPE;
    
    // 接口信号声明
    reg clk;
    reg reset;
    reg [1:0] data_type;
    reg mult_en;
    reg c_add_en;
    reg [`DATA_WIDTH-1:0] a_in;
    reg [`DATA_WIDTH-1:0] b_in;
    reg [`DATA_WIDTH-1:0] c_in;
    wire [`DATA_WIDTH-1:0] a_out;
    wire [`DATA_WIDTH-1:0] b_out;
    wire [`DATA_WIDTH-1:0] c_out;
    wire add_valid_o;


    pe uut (
        .clk(clk),
        .reset(reset),
        .data_type(data_type),
        .mult_en(mult_en),
        .c_add_en(c_add_en),
        .a_in(a_in),
        .b_in(b_in),
        .c_in(c_in),
        .a_out(a_out),
        .b_out(b_out),
        .c_out(c_out),
        .add_valid_o(add_valid_o)
    );

    // 时钟生成（200MHz）
    initial begin
        clk = 0;
        forever #2.5 clk = ~clk;
    end

    initial begin
        reset = 1;
        {mult_en, c_add_en} = 0;
        {a_in, b_in, c_in} = 0;
        data_type = 2'b10; // FP16模式
        #20 reset = 0;
        @(posedge clk);
        c_add_en <= 1;
        c_in <= {16'd0,16'h10};
        #10;
        @(posedge clk);
        mult_en <= 1;
        a_in <= {16'd0,16'hF18B};
        b_in <= {16'd0,16'h80A1};
        @(posedge clk);
        a_in <= {16'd0,16'hC149};
        b_in <= {16'd0,16'hDB2C};
        @(posedge clk);
        a_in <= {16'd0,16'hBAC3};
        b_in <= {16'd0,16'h7B87};
        @(posedge clk); 
        mult_en <= 0;
        #70;
        $stop;
    end
    endmodule